#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>

#define NUM 1024
//可进行的命令行操作个数：
#define OPT_NUM 64

#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3
char* myargv[OPT_NUM];
//用来接受命令行字符串
char commandline[NUM];

int lastcode = 0;
int lastsign = 0;


int redir_type = NONE_REDIR;
char* redirfile = NULL;//标识重定向的文件

#include <ctype.h>
void jump_space(char* start)
{
    while(isspace(*start))
    {
      ++start;
    }
}

void command_check(char* command)
{
  assert(command);
  char* start = command;
  char* end = command + strlen(command);
  while(start != end)
  {
    //输入重定向
    if(*start ==  '>')
    {
      //判断是否是追加
      *start = '\0';
      ++start;
      if(*start == '>')
      {
        redir_type = APPEND_REDIR;
        ++start;
      }
      else{
        redir_type = OUTPUT_REDIR;
      }
      jump_space(start);
      redirfile = start;
      break;
    }
    else if(*start == '<')
    {
      *start = '\0';
      redir_type = INPUT_REDIR;
      ++start;
      jump_space(start);
      redirfile = start;
      break;
    }
    else{
      ++start;
    }

  }
}

int main()
{
  while(1)
  {
    //重置一下
    redirfile = NULL;
    redir_type = NONE_REDIR;
    printf("用户名@主机名 当前路径# ");
    fflush(stdout);
    //输入
   char*s = fgets(commandline,sizeof(commandline)-1,stdin);
   assert(s != NULL);
   (void)s;
    //把最后的\n去掉
    commandline[strlen(commandline)-1] = 0;
    //分割字符串之前判断是否要重定向
    command_check(commandline);
    //以空格分割
    myargv[0] = strtok(commandline," ");
    int i = 1;

    //设置颜色
    if(myargv[0] != NULL && strcmp(myargv[0],"ls")==0)
    {
      myargv[i++] = (char*)"--color=auto";
    }

    while(myargv[i++] = strtok(NULL," "));
    //执行内建命令，在创建子进程之前完成
    if(myargv[0] != NULL && strcmp(myargv[0],"cd") == 0)
    {
      if(myargv[1] != NULL)
      {
        chdir(myargv[1]);
        //后面就不需要执行了
        continue;
      }
    }
    if(myargv[0] != NULL && strcmp(myargv[0],"echo") == 0)
    {
      if(strcmp(myargv[1],"$?") == 0)
      {
        printf("lastcode :%d lastsign :%d\n",lastcode,lastsign);
      }
      else{
        //其他结果都是直接打印到屏幕上
        printf("%s\n",myargv[1]);
      }
      continue;
    }
    //创建子进程，让子进程执行相关命令
    pid_t id = fork();
    assert(id != -1);
    if(id == 0)
    {
      //实现重定向
      switch(redir_type)
      {
        case NONE_REDIR:
          break;
        case INPUT_REDIR:
          {
          int fd = open(redirfile,O_RDONLY);
          assert(fd);
          dup2(fd,0);
          }
          break;
        case OUTPUT_REDIR:
        case APPEND_REDIR:
        {
          umask(0);
          int flag = O_WRONLY | O_CREAT;
          if(redir_type == OUTPUT_REDIR) 
          {
            flag |= O_TRUNC;
          }
          else{
            flag |= O_APPEND;
          }
          int fd = open(redirfile,flag ,0666);
          assert(fd);
          dup2(fd,1);
        }
          break;
        default:
          printf("bug\n");
          break;
      }
      execvp(myargv[0],myargv);
      exit(1);
    }
    //parent
    int status = 0;
    pid_t ret = waitpid(id,&status,0);
    assert(ret >0);
    lastcode = ((status>>8)&0xFF);
    lastsign = (status & 0x7F);

  }
}
